<?php

namespace System\library;

use System\library\Cli;
use System\library\utility\Validate;

/**
 * <b>Class</b> :        Session<br>
 * <b>Fonction</b> :     Class for gestion of a session
 * <br>
 * @version              1.0
 * @author               Steuf
 * @license              Licence publique générale GNU http://www.gnu.org/licenses/gpl.html
 * @copyright            Copyright 2011 - MidichloriansPHP and contributors
 * @package              System
 * @subpackage           library
 */
class Session {

    private $_lock = array();
    private $_datas = null;
    private static $_autoStart = true;
    private static $_started = false;

    private function __construct() {
        if (!extension_loaded('session'))
            throw new \Exception('Session extension not loaded try change your PHP configuration');
        $this->_datas = new \stdClass();
    }

    public static function getInstance() {
        try {
            if (self::$_autoStart && !Cli::isCliMode())
                self::startSession();
            if (!isset($_SESSION['Midi-chloriansPHP']) || !is_object($_SESSION['Midi-chloriansPHP']) || !$_SESSION['Midi-chloriansPHP'] instanceof Session)
                $_SESSION['Midi-chloriansPHP'] = new Session();
            return $_SESSION['Midi-chloriansPHP'];
        } catch (\Exception $e) {
            throw new \Exception('Session error : ' . $e);
        }
    }

    public static function isSessionStarted() {
        return self::$_started;
    }

    public function addVariable($key, $variable, $lock = false) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!Validate::isVariableName($key))
            throw new \Exception('The key must be a valid variable name');
        if (isset($this->_datas->{$key}) && $this->isLocked($key))
            throw new \Exception('You cannot set a variable at key "' . $key . '" because it is locked');
        $this->_lock[$key] = $lock;
        $this->_datas->{$key} = $variable;
    }

    public function getVariable($key) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!Validate::isVariableName($key))
            throw new \Exception('The key must be a valid variable name');
        if (!isset($this->_datas->{$key}))
            return null;
        return $this->_datas->{$key};
    }

    public function removeVariable($key) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!Validate::isVariableName($key))
            throw new \Exception('The key must be a valid variable name');
        if (isset($this->_datas->{$key}) && $this->isLocked($key))
            throw new \Exception('You cannot remove variable at key "' . $key . '" because it is locked');
        if (isset($this->_datas->{$key}))
            unset($this->_datas->{$key});
    }

    public function unLockVariable($key) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!Validate::isVariableName($key))
            throw new \Exception('The key must be a valid variable name');
        if (!isset($this->_datas->{$key}))
            throw new \Exception('Variable "' . $key . '" cannot be unlock because it undefined');
        $this->_lock[$key] = false;
    }

    public function lockVariable($key) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!Validate::isVariableName($key))
            throw new \Exception('The key must be a valid variable name');
        if (!isset($this->_datas->{$key}))
            throw new \Exception('Variable "' . $key . '" cannot be unlock because it undefined');
        $this->_lock[$key] = true;
    }

    public function isLocked($key) {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        if (!isset($this->_lock[$key]))
            return false;
        return $this->_lock[$key];
    }

    public function clear() {
        if (!self::isSessionStarted())
            throw new \Exception('Session must be started before use');
        $this->_datas = new \stdClass();
        $this->_lock = array();
    }

    public static function setAutoStart($bool) {
        if (!is_bool($bool))
            throw new \Exception('Parameter for autostart configuration must be a boolean');
        self::$_autoStart = $bool;
    }

    public static function startSession() {
        if (session_id() == '' && !Cli::isCliMode()) {
            if (!headers_sent()) {
                session_start();
                if (!key_exists('Midi-chloriansPHP', $_SESSION))
                    session_regenerate_id();
                self::$started = true;
            }else {
                throw new \Exception('Session isn\'t started and cannot be started because header is already send');
            }
        }
    }

    public static function regenerateId() {
        if (!self::isSessionStarted())
            self::startSession();
        else
            session_regenerate_id();
    }

    public static function unserialize($data, $putOnGlobal = false) {
        if (!is_string($data))
            throw new \Exception('Session data must be a string');
        $vars = preg_split('/([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff^|]*)\|/', $data, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
        $arrayLenght = count($vars);
        $result = array();
        for ($i = 0; $i < $arrayLenght; $i++)
            $result[$vars[$i++]] = unserialize($vars[$i]);
        if ($putOnGlobal)
            $_SESSION = $result;
        return $result;
    }

}

?>
